#ifndef RISCV_CPU_H
#define RISCV_CPU_H

#include "iomem.h"

#define MIP_USIP (1 << 0)
#define MIP_SSIP (1 << 1)
#define MIP_HSIP (1 << 2)
#define MIP_MSIP (1 << 3)
#define MIP_UTIP (1 << 4)
#define MIP_STIP (1 << 5)
#define MIP_HTIP (1 << 6)
#define MIP_MTIP (1 << 7)
#define MIP_UEIP (1 << 8)
#define MIP_SEIP (1 << 9)
#define MIP_HEIP (1 << 10)
#define MIP_MEIP (1 << 11)

typedef struct {
    #define TLB_SIZE 256
    uint64_t vaddr;
    uintptr_t mem_addend;
} TLBEntry;

typedef struct RISCVCPUState {
    uint64_t pc;
    uint64_t reg[32];

    int32_t n_cycles; /* only used inside the CPU loop */
    uint64_t insn_counter;
    BOOL power_down_flag;
    int pending_exception; /* used during MMU exception handling */
    
    uint64_t pending_tval;

    uint64_t mstatus;
    uint64_t mtvec;
    uint64_t mscratch;
    uint64_t mepc;
    uint64_t mcause;
    uint64_t mtval;
    uint64_t mhartid;
    uint32_t misa;
    uint32_t mie;
    uint32_t mip;
    uint32_t medeleg;
    uint32_t mideleg;
    uint32_t mcounteren;

    uint64_t stvec;
    uint64_t sscratch;
    uint64_t sepc;
    uint64_t scause;
    uint64_t stval;

    uint64_t satp;
    uint32_t scounteren;

    uint64_t load_res;

    uint8_t cur_xlen;  /* current XLEN value, <= MAX_XLEN */
    uint8_t priv; /* see PRV_x */
    uint8_t fs; /* MSTATUS_FS value */
    uint8_t mxl; /* MXL field in MISA register */

    PhysMemoryMap *mem_map;

    TLBEntry tlb_read[TLB_SIZE];
    TLBEntry tlb_write[TLB_SIZE];
    TLBEntry tlb_code[TLB_SIZE];
} RISCVCPUState;

RISCVCPUState *riscv_cpu_init (PhysMemoryMap * mem_map);

uint64_t riscv_cpu_get_cycles (RISCVCPUState *s);

uint32_t riscv_cpu_get_mip (RISCVCPUState *s);

void riscv_cpu_set_mip (RISCVCPUState *s, uint32_t mask);

void riscv_cpu_reset_mip (RISCVCPUState *s, uint32_t mask);

void riscv_cpu_interp (RISCVCPUState *s, int n_cycles);

#endif